home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
dc1
/
lex.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
28KB
|
1,379 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
/*
* LEX.C
*/
/*
** $Filename: lex.c $
** $Author: dice $
** $Revision: 30.326 $
** $Date: 1995/12/24 06:09:42 $
** $Log: lex.c,v $
* Revision 30.326 1995/12/24 06:09:42 dice
* .
*
* Revision 30.156 1995/01/11 05:04:48 dice
* MINIDICE2 additions - check for input file too large (disabled, not
* in MINIDICE release)
*
* Revision 30.5 1994/06/13 18:37:31 dice
* .
*
* Revision 30.0 1994/06/10 18:04:52 dice
* .
*
* Revision 1.5 1994/04/15 21:15:00 jtoebes
* Correct dicecache compile problems.
* Also fixed warning for hex constants in strings gobbling up characters.
*
* Revision 1.4 1993/11/14 17:22:10 jtoebes
* Eliminate reference to lex.h (empty include file).
*
* Revision 1.3 1993/09/12 17:16:42 jtoebes
* Fixed BUG00120 - \x does not allow a single hex character.
* Changed the parsing so that it is more in line with ANSI. \x will
* parse as many characters as are hex. also fixed the octal parsing code.
*
* Revision 1.2 1993/09/06 10:15:48 jtoebes
* Fixed BUG01098 - Stack overflow with blank lines causing recursion.
*
**/
#include "defs.h"
#ifdef _DCC
#include <lib/misc.h> /* get _parseargs1() & 2 */
#include <ioctl.h>
#include <clib/dicecache_protos.h>
#endif
Prototype void InitLex(void);
Prototype short LexSimpleToken(void);
Prototype short LexLineFeed(void);
Prototype short LexWhiteSpace(void);
Prototype short LexTLex(void);
Prototype short LexSymbol(void);
Prototype short LexInteger(void);
Prototype short LexDecimal(void);
Prototype short LexCharConst(void);
Prototype short LexString(void);
Prototype short LexToken(void);
/*Prototype short LexSymbolRef(short, long);*/
Prototype short LexOctal(ubyte, long);
Prototype short LexHex(ubyte, long);
Prototype short LexFloating(long, long);
Prototype void PushLexFile(char *, short, long, long);
Prototype short PopLexFile(void);
Prototype int SpecialChar(long *);
Prototype long CharToNibble(short);
Prototype short SkipToken(short, short);
Prototype char *TokenToStr(short);
Prototype long FindLexFileLine(long, char **, long *, long *);
Prototype short FindLexCharAt(long);
Prototype long LexIntConst;
Prototype char *LexStrConst; /* also flt constant */
Prototype long LexStrLen;
Prototype Symbol *LexSym;
Prototype void *LexData;
Prototype char LexHackColon;
Prototype char LexUnsigned;
Prototype char FileName[128];
Prototype char SymbolSpace[256];
Prototype long Depth;
Prototype short ErrorInFileValid;
Prototype long LexCacheHits;
Prototype long LexCacheMisses;
Prototype LexFileNode *LFBase;
Prototype short (*LexDispatch[256])(void);
LexFileNode *LFBase;
long LexIntConst;
char *LexStrConst; /* also flt constant */
long LexStrLen;
Symbol *LexSym;
void *LexData;
char LexHackColon;
char LexUnsigned;
char FileName[128];
char SymbolSpace[256];
long Depth;
long LexCacheHits;
long LexCacheMisses;
#ifdef NOTDEF
xSymbol *LexSymRefSym[256];
xshort LexSymRefIdx;
#endif
short ErrorInFileValid;
#define TLF 1
#define TWHITE 2
#define TLEX 3
#define TALPHA 4
#define TZERO 5
#define TNUM 6
#define TCHARC 7
#define TSTRC 8
#define TTOKEN 9
#define TALPHX 10
static const char TokenType[256] = {
/*00*/ 0, 0, 0, 0, 0, 0, 0, 0,
0, TWHITE, TLF, 0, TWHITE, TWHITE, 0, 0,
/*10*/ 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
/*20*/ TWHITE, 0, TSTRC, 0, 0, 0, 0, TCHARC,
0, 0, 0, 0, 0, 0, 0, 0,
/*30*/ TZERO, TNUM, TNUM, TNUM, TNUM, TNUM, TNUM, TNUM,
TNUM, TNUM, 0, 0, 0, 0, 0, 0,
/*40*/ 0 , TALPHX, TALPHX, TALPHX, TALPHX, TALPHX, TALPHX, TALPHA,
TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA,
/*50*/ TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA,
TALPHA, TALPHA, TALPHA, 0, 0, 0, 0, TALPHA,
/*60*/ 0 , TALPHX, TALPHX, TALPHX, TALPHX, TALPHX, TALPHX, TALPHA,
TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA,
/*70*/ TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA,
TALPHA, TALPHA, TALPHA, 0, 0, 0, 0, 0,
/*80*/ TTOKEN, TTOKEN, TTOKEN, TTOKEN, TTOKEN, TTOKEN, TTOKEN, TTOKEN
};
/*short LexDispatch*/
short (*LexDispatch[256])(void);
short (*LexFuncTable[])(void) = {
LexSimpleToken,
LexLineFeed,
LexWhiteSpace,
LexTLex,
LexSymbol,
LexInteger,
LexDecimal,
LexCharConst,
LexString,
LexToken,
LexSymbol
};
void
InitLex(void)
{
short i;
Assert(1); /* filler to avoid gnu compiler warnings */
{
char *ss = SymbolSpace;
for (i = 'a'; i <= 'z'; ++i)
ss[i] = 1;
for (i = 'A'; i <= 'Z'; ++i)
ss[i] = 1;
for (i = '0'; i <= '9'; ++i)
ss[i] = 1;
ss['_'] = 1;
}
for (i = 0; i < 256; ++i)
LexDispatch[i] = LexFuncTable[(short)TokenType[i]];
}
/*
* Lexical file push/pop
*/
void
PushLexFile(char *name, short nameLen, long begPos, long bytes)
{
LexFileNode *lf = zalloc(sizeof(LexFileNode) + nameLen + 1);
if (bytes == -2) {
lf->lf_FileName = "";
lf->lf_Fi = (FILE *)name;
} else {
lf->lf_FileName = (char *)(lf + 1);
movmem(name, lf->lf_FileName, nameLen);
lf->lf_FileName[nameLen] = 0;
if ((lf->lf_Fi = fopen(lf->lf_FileName, "r")) == NULL)
zerror(EFATAL_CANT_OPEN_FILE, lf->lf_FileName);
}
if (bytes < 0) {
fseek(lf->lf_Fi, 0L, 2);
if ((bytes = ftell(lf->lf_Fi)) < 0)
zerror(EFATAL_INPUT_NOT_SEEKABLE);
fseek(lf->lf_Fi, begPos, 0);
} else {
fseek(lf->lf_Fi, begPos, 0);
}
#ifdef MINIDICE2
if (bytes > 65530) {
zerror(EFATAL_INPUT_TOO_LARGE, bytes);
}
#endif
#ifdef _DCC
/*
* HACK! we should really add an IODOM_CACHE field and make ioctl()
* return it for cached files.
*/
if (ioctl(fileno(lf->lf_Fi), IOC_DOMAIN, NULL) != IODOM_AMIGADOS) {
/*
* DICECACHE support - directly reference the cache. Note that
* we cannot close the file handle without invalidating our
* cache entry and, since we reference pointers into the buffer,
* that means we cannot close any handles until the program is
* done.
*/
struct {
void *cfh_Cn; // dicecache.library descriptor
long cfh_Size;
long cfh_Pos;
} *cfh = (void *)ioctl(fileno(lf->lf_Fi), IOC_GETDESC, NULL);
lf->lf_Buf = DiceCacheSeek(cfh->cfh_Cn, begPos, &lf->lf_Size);
lf->lf_Size = bytes; /* XXX check against lf_Size */
/*fprintf(stderr, "PUSH-CACHED %08lx %d\n", lf->lf_Buf, lf->lf_Size);*/
} else
#endif
{
/*fprintf(stderr, "PUSH-UNCACHED %d\n", bytes);*/
if ((lf->lf_Buf = malloc(bytes + 4)) != NULL) {
fread(lf->lf_Buf, bytes, 1, lf->lf_Fi);
clrmem(lf->lf_Buf + bytes, 4);
lf->lf_Size = bytes;
} else {
NoMem();
}
}
lf->lf_Next = LFBase;
lf->lf_Index= 0;
lf->lf_BaseIndex = 0;
LFBase = lf;
}
short
PopLexFile(void)
{
/*fprintf(stderr, "POPLEX %d\n", LFBase->lf_Index);*/
if (LFBase) {
LexFileNode *lf;
if ((lf = LFBase->lf_Next) != NULL) {
LFBase = lf;
return(1);
}
/*
* don't clear out last LFBase because lexical routines presume
* one exists!
*/
}
return(0);
}
short
LexToken(void)
{
long i = LFBase->lf_Index;
ubyte *ptr = LFBase->lf_Buf + i;
LFBase->lf_Index = i + 2;
#ifdef NOTDEF
x if (*ptr == TokCppRef_Byte) {
x return(LexSymbolRef(ptr[1], i + 2));
x } else
#endif
{
return((ptr[0] << 12) | ptr[1]);
}
}
short
LexLineFeed(void)
{
long i = LFBase->lf_Index;
char *ptr = LFBase->lf_Buf + i;
char *base;
do {
base = ptr;
while (*ptr == '\n') /* optimize \n\n\n... */
++ptr;
while (*ptr == '#') { /* # line "file" depth */
++ptr;
while (*ptr == ' ' || *ptr == 9)
++ptr;
/*
* Ignore # line constructs, handle others
*/
if (*ptr < '0' || *ptr > '9') {
if (strncmp(ptr, "pragma", 6) == 0) {
ptr += 6;
while (*ptr == ' ' || *ptr == 9)
++ptr;
#ifdef REGISTERED
if (strncmp(ptr, "libcall", 7) == 0) {
ProcessLibCallPragma(ptr + 7, 0);
} else if (strncmp(ptr, "syscall", 7) == 0) {
ProcessLibCallPragma(ptr + 7, 1);
} else
#endif
if (strncmp(ptr, "DCCOPTS", 7) == 0) {
/*
* Process #pragma DCCOPTS. Note that
* associated memory is permanent since some options
* refer directly to the parsed string.
*/
#ifdef _DCC
char *p2 = ptr;
short len;
short ac;
char **av;
while (*p2 && *p2 != '\n')
++p2;
len = p2 - ptr;
movmem(ptr, p2 = zalloc(len + 1), len);
if (ac = _parseargs1(p2 + 7, len - 7)) {
av = zalloc((ac + 2) * 4);
_parseargs2(p2 + 7, av + 1, ac);
++ac;
ParseOpts(ac, av, 0);
}
#endif
}
} else if (strncmp(ptr, "precomp", 7) == 0) {
long begPos;
long bytes;
char *name;
short nameLen;
for (; *ptr && *ptr != ' '; ++ptr)
;
begPos = atoi(ptr);
for (ptr = ptr + 1; *ptr && *ptr != ' '; ++ptr)
;
bytes = atoi(ptr);
while (*ptr && *ptr != '\"')
++ptr;
name = ptr + 1;
for (ptr = ptr + 1; *ptr && *ptr != '\"'; ++ptr)
;
nameLen = ptr - name;
while (*ptr && *ptr != '\n')
++ptr;
LFBase->lf_Index = ptr - LFBase->lf_Buf + 1;
PushLexFile(name, nameLen, begPos, bytes);
return(GetToken());
} else if (strncmp(ptr, "debug", 5) == 0) {
DDebug = atoi(ptr + 5);
} else {
/* ignore... # line (parsed for error conditions only) */
}
}
while (*ptr && *ptr != '\n')
++ptr;
while (*ptr == '\n')
++ptr;
}
while (*ptr == ' ' || *ptr == '\t') /* optimization */
++ptr;
LFBase->lf_Index = ptr - LFBase->lf_Buf;
} while (base != ptr);
return(GetToken());
}
short
LexWhiteSpace(void)
{
const ubyte *tt = TokenType;
const ubyte *ptr = LFBase->lf_Buf + LFBase->lf_Index;
while (tt[*ptr] == TWHITE)
++ptr;
LFBase->lf_Index = (char *)ptr - (char *)LFBase->lf_Buf;
return(GetToken());
}
short
LexTLex(void)
{
return(GetToken());
}
/*
* Lexical Symbol. Symbol-init has already predefined most symbols
*/
short
LexSymbol(void)
{
const ubyte *base = LFBase->lf_Buf + LFBase->lf_Index;
const ubyte *ptr = base;
{
ubyte *ss = SymbolSpace;
while (ss[*ptr])
++ptr;
}
LexSym = MakeSymbol(base, ptr - base, TokId, NULL);
LexData= LexSym->Data;
#ifdef NOTDEF
x LexSymRefSym[LexSymRefIdx] = LexSym;
x LexSymRefIdx = (LexSymRefIdx + 1) & 0xFF;
#endif
{
const ubyte *tt = TokenType;
while (tt[*ptr] == TWHITE)
++ptr;
}
LFBase->lf_Index = (char *)ptr - (char *)LFBase->lf_Buf;
if (*ptr != ':') {
LexHackColon = 0;
return(LexSym->LexId);
} else {
LexHackColon = 1;
switch(LexSym->LexId) {
case TokVarId:
case TokCase:
case TokDefault:
case TokEnumConst:
return(LexSym->LexId);
default:
return(TokId);
}
}
}
#ifdef NOTDEF
x
x/*
x * precompiled header support from DCPP, DCPP recognizes a previously
x * defined symbol and gives a simple reference index with which we
x * can look up the symbol instantly.
x */
x
xshort
xLexSymbolRef(relId, i)
xshort relId;
xlong i;
x{
x relId = (LexSymRefIdx - relId) & 0xFF;
x LexSym = LexSymRefSym[relId];
x
x#ifdef NOTDEF
x LexSym = MakeSymbol(LexSymRefPtr[relId], LexSymRefLen[relId], TokId, NULL);
x#endif
x LexData = LexSym->Data;
x
x if (LexBuf[i] == ':') {
x LexHackColon = 1;
x
x switch(LexSym->LexId) {
x case TokVarId:
x case TokCase:
x case TokDefault:
x case TokEnumConst:
x return(LexSym->LexId);
x default:
x return(TokId);
x }
x } else {
x LexHackColon = 0;
x return(LexSym->LexId);
x }
x}
x
#endif
/*
* Hex or Octal
*/
short
LexInteger(void)
{
long i = LFBase->lf_Index + 1;
ubyte c = LFBase->lf_Buf[i++]; /* second char */
if (c == 'x' || c == 'X')
return(LexHex(LFBase->lf_Buf[i], i + 1));
return(LexOctal(c, i));
}
short
LexOctal(ubyte c, long i)
{
long v = 0;
long b = i - 2; /* if flt */
char *lexBuf = LFBase->lf_Buf;
LexUnsigned = 0;
while (c >= '0' && c <= '7') {
v = (v << 3) + (c - '0');
c = lexBuf[i++];
}
if (v & 0x80000000)
LexUnsigned = 1;
while (c == 'L' || c == 'l' || c == 'U' || c == 'u') {
if (c == 'u' || c == 'U')
LexUnsigned = 1;
c = lexBuf[i++];
}
if (c == '.' || c == 'e' || c == 'E')
return(LexFloating(b, i));
LFBase->lf_Index = i - 1;
LexIntConst = v;
return(TokIntConst);
}
short
LexDecimal(void)
{
char *lexBuf = LFBase->lf_Buf;
long i = LFBase->lf_Index;
ubyte c = lexBuf[i++];
long v = 0;
long b = i - 1; /* if flt */
LexUnsigned = 0;
while (c >= '0' && c <= '9') {
v = (v * 10) + (c - '0');
c = lexBuf[i++];
}
if (v & 0x80000000)
LexUnsigned = 1;
while (c == 'L' || c == 'l' || c == 'U' || c == 'u') {
if (c == 'u' || c == 'U')
LexUnsigned = 1;
c = lexBuf[i++];
}
if (c == '.' || c == 'e' || c == 'E')
return(LexFloating(b, i - 1));
LFBase->lf_Index = i - 1;
LexIntConst = v;
return(TokIntConst);
}
short
LexHex(ubyte c, long i)
{
long v = 0;
char *lexBuf = LFBase->lf_Buf;
for (;;) {
if (c >= '0' && c <= '9')
v = (v << 4) + (c - '0');
else if (c >= 'a' && c <= 'f')
v = (v << 4) + (c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
v = (v << 4) + (c - 'A' + 10);
else
break;
c = lexBuf[i++];
}
while (c == 'L' || c == 'l' || c == 'U' || c == 'u')
c = lexBuf[i++];
LFBase->lf_Index = i - 1;
LexIntConst = v;
LexUnsigned = 1;
return(TokIntConst);
}
short
LexFloating(b, i)
long b, i;
{
char *lexBuf = LFBase->lf_Buf;
ubyte c = lexBuf[i++];
LexStrConst = lexBuf + b;
if (c == '.')
c = lexBuf[i++];
while (c >= '0' && c <= '9')
c = lexBuf[i++];
if (c == 'e' || c == 'E') { /* En E+n E-n */
/*
* used to set lexBuf[-1] to 'E' to fix bug in afp()
* but no longer since lexBuf may be direct from the cache!
*/
c = lexBuf[i++];
if (c == '+' || c == '-')
c = lexBuf[i++];
while (c >= '0' && c <= '9')
c = lexBuf[i++];
}
LexStrLen = i - b - 1;
LexData = &DoubleType;
switch(c) {
case 'f':
case 'F':
LexData = &FloatType;
++i;
break;
case 'l':
case 'L':
LexData = &LongDoubleType;
++i;
break;
}
LFBase->lf_Index = i - 1;
return(TokFltConst);
}
short
LexCharConst(void)
{
char *lexBuf = LFBase->lf_Buf;
long i = LFBase->lf_Index + 1;
ubyte c = lexBuf[i++];
short cnt = 0;
long v = 0;
while (c != '\'') {
if (c == 0)
zerror(EFATAL_UNEXPECTED_EOF);
if (c == '\\') {
if (lexBuf[i] == '\n') {
c = lexBuf[i+1];
i += 2;
continue;
}
c = SpecialChar(&i);
}
v = (v << 8) | c;
++cnt;
c = lexBuf[i++];
}
if (cnt > 4)
zerror(EWARN_CHAR_CONST_TOO_LONG);
if (cnt == 1)
v = (char)v;
LFBase->lf_Index = i;
LexIntConst = v;
LexUnsigned = 0;
return(TokIntConst);
}
/*
* Extract a lexical string. Since we may be referencing out of a
* file cache, and since we must terminate the string with \0, we
* therefore have to make a copy.
*/
short
LexString(void)
{
long i;
long n;
ubyte c;
ubyte nlisc = 0;
ubyte pass = 0;
char *ptr = NULL;
char *lexBuf = LFBase->lf_Buf;
for (pass = 0; pass < 2; ++pass) {
i = LFBase->lf_Index;
n = 0;
for (;;) {
for (++i; (c = lexBuf[i]) != '\"'; ++i) {
if (c == 0)
zerror(EFATAL_UNEXPECTED_EOF);
if (c == '\n' && nlisc == 0) {
nlisc = 1;
zerror(EWARN_NEWLINE_IN_STRING_CONST);
}
if (c == '\\') {
++i;
if (lexBuf[i] == '\n')
continue;
c = SpecialChar(&i);
--i;
}
if (ptr)
ptr[n] = c;
++n;
}
/*
* Check for concactenated strings
*/
for (c = lexBuf[++i]; TokenType[c] == TWHITE || TokenType[c] == TLF; c = lexBuf[++i])
;
if (c != '\"')
break;
}
if (pass == 0)
ptr = zalloc(n + 1);
else
ptr[n] = 0;
++n;
}
LFBase->lf_Index = i;
LexStrConst = ptr;
LexStrLen = n;
return(TokStrConst);
}
#ifdef NOTDEF
xshort
xLexString(void)
x{
x long i = LexIdx + 1;
x ubyte c;
x ubyte nlisc = 0;
x long b = i; /* base of string frag */
x long j = i; /* actual write idx */
x long appnl = 0;
x
x for (;;) {
x c = LexBuf[i++];
x
x while (c != '\"') {
x if (c == 0)
x zerror(EFATAL_UNEXPECTED_EOF);
x if (c == '\n' && nlisc == 0) {
x nlisc = 1;
x zerror(EWARN_NEWLINE_IN_STRING_CONST);
x }
x if (c == '\\') {
x if (LexBuf[i] == '\n') {
x c = LexBuf[i+1];
x i += 2;
x ++appnl;
x continue;
x }
x c = SpecialChar(&i);
x }
x LexBuf[j++] = c;
x c = LexBuf[i++];
x }
x /*
x * string LexBuf + b of length (j - b). Check for concactenated strs
x * as per ANSI. Track file line numbering so we can recover it
x * later.
x */
x
x c = LexBuf[i];
x while (TokenType[c] == TWHITE || TokenType[c] == TLF) {
x if (c == '\n')
x ++appnl;
x c = LexBuf[++i];
x }
x if (c != '\"')
x break;
x ++i;
x }
x
x /*
x * Terminating \0 is implicit to string constants, e.g. sizeof("abc").
x * Note that this also serves as a start-string indication for the
x * error routines (to avoid embedded newlines)
x */
x
x LexBuf[j++] = 0;
x LexIdx = i;
x LexStrConst = (char *)LexBuf + b;
x LexStrLen = j - b;
x
x /*
x * Clear out extra junk
x */
x
x while (j + appnl < i)
x LexBuf[j++] = ' ';
x
x /*
x * Mark area as munged
x */
x
x MarkAreaMunged(b, j);
x
x /*
x * Recover dummy newlines that were embedded in the string so line
x * number tracking doesn't screw up
x */
x
x while (appnl--)
x LexBuf[j++] = '\n';
x
x return(TokStrConst);
x}
#endif
/*
* LexSimpleToken() returns simple tokens such as +, ++, etc..
*/
short
LexSimpleToken(void)
{
ubyte *ptr = LFBase->lf_Buf + LFBase->lf_Index + 1;
short token;
switch(ptr[-1]) {
case '!': /* !, != */
if (*ptr == '=') {
token = TokNotEq;
++ptr;
break;
}
token = TokNot;
break;
case '%': /* %, %= */
if (*ptr == '=') {
token = TokPercentEq;
++ptr;
break;
}
token = TokPercent;
break;
case '&': /* &, &&, &= */
if (*ptr == '&') {
token = TokAndAnd;
++ptr;
break;
}
if (*ptr == '=') {
token = TokAndEq;
++ptr;
break;
}
token = TokAnd;
break;
case '(':
token = TokLParen;
break;
case ')':
token = TokRParen;
break;
case '*': /* *, *= */
if (*ptr == '=') {
token = TokStarEq;
++ptr;
break;
}
token = TokStar;
break;
case '+': /* +, ++, += */
if (*ptr == '+') {
token = TokPlPl;
++ptr;
break;
}
if (*ptr == '=') {
token = TokPlEq;
++ptr;
break;
}
token = TokPl;
break;
case ',':
token = TokComma;
break;
case '-': /* -, --, -=, -> */
switch(*ptr) {
case '-':
token = TokMiMi;
++ptr;
break;
case '=':
token = TokMiEq;
++ptr;
break;
case '>':
token = TokStrInd;
++ptr;
break;
default:
token = TokMi;
break;
}
break;
case '.':
if (*ptr >= '0' && *ptr <= '9') {
long i = (char *)ptr - (char *)LFBase->lf_Buf - 1;
return(LexFloating(i, i));
}
if (*ptr == '.' && ptr[1] == '.') {
token = TokDotDotDot;
ptr += 2;
break;
}
token = TokStrElm;
break;
case '/': /* /, /= */
if (*ptr == '=') {
token = TokDivEq;
++ptr;
break;
}
token = TokDiv;
break;
case '<': /* <, <<, <<=, <= */
if (*ptr == '<') {
if (ptr[1] == '=') {
token = TokLtLtEq;
ptr += 2;
break;
}
token = TokLtLt;
++ptr;
break;
}
if (*ptr == '=') {
token = TokLtEq;
++ptr;
break;
}
token = TokLt;
break;
case '=':
if (*ptr == '=') {
token = TokEqEq;
++ptr;
break;
}
token = TokEq;
break;
case '>':
if (*ptr == '>') {
if (ptr[1] == '=') {
token = TokGtGtEq;
ptr += 2;
break;
}
token = TokGtGt;
++ptr;
break;
}
if (*ptr == '=') {
token = TokGtEq;
++ptr;
break;
}
token = TokGt;
break;
case '?':
token = TokQuestion;
break;
case ':':
token = TokColon;
break;
case '[':
token = TokLBracket;
break;
case ']':
token = TokRBracket;
break;
case '^':
if (*ptr == '=') {
token = TokCaratEq;
++ptr;
break;
}
token = TokCarat;
break;
case '|':
if (*ptr == '|') {
token = TokOrOr;
++ptr;
break;
}
if (*ptr == '=') {
token = TokOrEq;
++ptr;
break;
}
token = TokOr;
break;
case '~':
token = TokTilde;
break;
case '{':
token = TokLBrace;
break;
case '}':
token = TokRBrace;
break;
case ';':
token = TokSemi;
break;
case 0: /* force table lookup for critical code */
if (PopLexFile()) {
return(GetToken());
}
/*
* Do not update LexIdx
*/
return(0);
case '#': /* hack to handle # directive on line 1 */
if (LFBase->lf_Index == 0)
return(LexLineFeed());
/* fall through */
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
default:
zerror(EWARN_ILLEGAL_CHAR, ptr[-1], ptr[-1]);
token = TokSemi;
break;
}
LFBase->lf_Index = (char *)ptr - (char *)LFBase->lf_Buf;
return(token);
}
/*
* MISC
*
*/
int
SpecialChar(pi)
long *pi;
{
long i = *pi;
int c = LFBase->lf_Buf[i];
int v = 0;
*pi = ++i;
switch(c) {
case 10: /* a newline! */
c = LFBase->lf_Buf[i];
*pi = ++i;
return(c);
break;
case 'n':
return(10);
case 'r':
return(13);
case 't':
return(9);
case 'f':
return(12);
case 'v':
return(11);
case 'a':
return(7);
case 'b':
return(8);
case 'x':
for(;;)
{
c = LFBase->lf_Buf[i];
switch(TokenType[c])
{
case TALPHX:
c = (c & 7) + 9; /* The & 7 makes the Upper and lower case */
/* characters appear the same */
break;
case TNUM:
case TZERO:
c -= '0';
break;
default:
if ((i - *pi) > 2)
{
zerror(EWARN_HEX_CONST_TRUNCATED);
}
*pi = i;
return(v);
}
i++;
v <<= 4;
v += c;
}
default:
{
int cnt = 0;
while ((cnt < 3) && (c >= '0') && (c <= '7'))
{
v = (v << 3) | (c - '0');
c = LFBase->lf_Buf[i];
i++;
cnt++;
}
if (cnt)
i--;
else
v = c;
*pi = i;
return(v);
}
}
}
long
CharToNibble(short c)
{
if (c >= '0' && c <= '9')
return(c - '0');
return((c | 0x20) - 'a' + 10);
}
short
SkipToken(short t, short expect)
{
if (t == expect)
return(GetToken());
zerror(EERROR_UNEXPECTED_TOKEN, TokenToStr(t), TokenToStr(expect));
return(t);
}
char *
TokenToStr(short t)
{
switch(t) {
case TokComma:
return(",");
case TokSemi:
return(";");
case TokLParen:
return("(");
case TokRParen:
return(")");
case TokLBrace:
return("{");
case TokRBrace:
return("}");
case TokColon:
return(":");
case TokLBracket:
return("[");
case TokRBracket:
return("]");
default:
return("<unknown>");
}
}
/*
* Find the line number associated with a lexical offset
*/
long
FindLexFileLine(lexIdx, plexFile, plexFileNameLen, plexIdxBeg)
long lexIdx;
char **plexFile;
long *plexFileNameLen;
long *plexIdxBeg;
{
long i;
char *ptr;
long lexLine = -1;
static long CacheLexIdx = -1;
static long CacheLexLine;
static char *CacheLexFile;
static long CacheLexFileNameLen;
/*
* find start of line
*/
*plexIdxBeg = lexIdx;
*plexFile = "";
if (LFBase == NULL)
return(0);
for (i = lexIdx, ptr = LFBase->lf_Buf + i; i > 0; --i) {
if (ptr[-1] == '\n' /*&& !OffsetMunged(i-1)*/) {
*plexIdxBeg = i;
break;
}
--ptr;
}
/*printf(";i %d/%d:%c\n", i, LFBase->lf_Buf[i], LFBase->lf_Buf[i]);*/
if (i == CacheLexIdx) {
*plexFile = CacheLexFile;
*plexFileNameLen= CacheLexFileNameLen;
*plexIdxBeg = i;
return(CacheLexLine);
}
/*
* reverse scan for '# <line> "<file>"'
*/
while (i >= 0) {
if (i == CacheLexIdx) {
*plexFile = CacheLexFile;
*plexFileNameLen = CacheLexFileNameLen;
lexLine += CacheLexLine + 1;
++LexCacheHits;
break;
}
if (*ptr == '#' && (i == 0 || (ptr[-1] == '\n' /*&& !OffsetMunged(i)*/))) {
short j;
char c;
for (j = 1; (c = ptr[j]) == ' ' || c == '\t'; ++j)
;
if ((c >= '0' && c <= '9') || c == '-') {
lexLine += atoi(ptr + j);
while ((c = ptr[j]) && c != '\"')
++j;
*plexFile = ptr + j + 1;
*plexFileNameLen = strchr(*plexFile, '\"') - *plexFile;
if (*plexFileNameLen < 0)
*plexFileNameLen = 0;
CacheLexFile = *plexFile;
CacheLexFileNameLen = *plexFileNameLen;
++LexCacheMisses;
break;
}
}
if (*ptr == '\n'/* && !OffsetMunged(i)*/)
++lexLine;
--i;
--ptr;
}
CacheLexLine = lexLine;
CacheLexIdx = *plexIdxBeg;
return(lexLine);
}
short
FindLexCharAt(i)
long i;
{
if (LFBase) {
if (ftell(LFBase->lf_Fi) != i)
fseek(LFBase->lf_Fi, i, 0);
return(getc(LFBase->lf_Fi));
}
return(EOF);
}